package com.example.demo.Utils;

import io.jsonwebtoken.*;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyStore;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JavaWebTokenUtils
 *
 *         String header = "{\"alg\":\""+CLAIM_KEY_METHOD+"\"}";
 *         String claims = "{\"sub\":\""+userDetails.getUsername() +"\"}";
 *         Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compactJws);
 *         Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
 *         String jws = Jwts.builder().setSubject("Joe").signWith(key).compact();
 *
 *         String encodedHeader = Base64Utils.encodeToString(header.getBytes(StandardCharsets.UTF_8));
 *        String encodedClaims = Base64Utils.encodeToString(claims.getBytes(StandardCharsets.UTF_8));
 *         String concatenated = encodedHeader + "." + encodedClaims;
 *         SecretKey secretKey = new SecretKeySpec(CLAIM_KEY_SECRET.getBytes(), SignatureAlgorithm.HS256.getJcaName());
 *         byte[] signature = hmacSha256( concatenated, secretKey );
 *         return concatenated + '.' + base64URLEncode( signature );
 *
 *
 *
 *     The JWT specification identifies 12 standard signature algorithms - 3 secret key algorithms and 9 asymmetric key algorithms - identified by the following names:
 *     HS256: HMAC using SHA-256
 *     HS384: HMAC using SHA-384
 *     HS512: HMAC using SHA-512
 *     ES256: ECDSA using P-256 and SHA-256
 *     ES384: ECDSA using P-384 and SHA-384
 *     ES512: ECDSA using P-521 and SHA-512
 *     RS256: RSASSA-PKCS-v1_5 using SHA-256
 *     RS384: RSASSA-PKCS-v1_5 using SHA-384
 *     RS512: RSASSA-PKCS-v1_5 using SHA-512
 *     PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256
 *     PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
 *     PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
 *
 *
 *         iss：该JWT的签发者
 *          sub：该JWT所面向的用户
 *          aud：接收该JWT的一方
 *          exp（expires）：什么时候过期，这里是一个Unit的时间戳
 *          iat（issued at）：在什么时候签发的
 *
 *     jwt =  eh +  ec + '.' + encode( hmacSha256(  eh +  ec, key ))
 *          @blame 吴经纶
 *          
 *      在每次获取token信息  如果有设置生命周期且超过生命周期 则会报错
 */

public class JavaWebTokenUtils {
    private static final long serialVersionUID = -5625635588908941275L;

    private static final String CLAIM_KEY_NAME = "sub";
    private static final String CLAIM_KEY_METHOD = "HS256";

    private static final String CLAIM_KEY_SECRET = "WUJINGLUN";

    public static String generateToken(UserDetails userDetails) throws NullPointerException,
            ExpiredJwtException, UnsupportedJwtException,SignatureException,IllegalArgumentException {
        if (userDetails.getUsername()==null){
            throw new NullPointerException("用户名为空");
        }
        if (userDetails.getPassword()==null){
            throw new NullPointerException("密码为空");
        }
        return Jwts.builder()
                .claim("role",userDetails.getAuthorities())
                .setSubject(userDetails.getUsername())
                .setIssuer(CLAIM_KEY_NAME)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24*12))
                .signWith(SignatureAlgorithm.HS256,CLAIM_KEY_SECRET)
                .compact();
    }
    public static Date getDateFromToken(String token) throws NullPointerException,
            ExpiredJwtException, UnsupportedJwtException,SignatureException,IllegalArgumentException
    {
        final Claims claims = Jwts.parser().setSigningKey(CLAIM_KEY_SECRET).parseClaimsJws(token).getBody();
        return  claims.getExpiration();
    }
//
//    public String refreshToken(String token) {
//        ...
//    }
//
    public static Boolean validateToken(String token, String userName,RedisUtils redisUtils) throws NullPointerException,
            ExpiredJwtException, UnsupportedJwtException,SignatureException,IllegalArgumentException{
        if (redisUtils.hasKey(userName))
        {
            return redisUtils.get(userName).toString().replace(ConstUtils.TokenUtils.TOKEN_PREFIX,"").equals(token);
        }
        return false;
    }

    public static String getUsernameFromToken(String token) throws NullPointerException,
            ExpiredJwtException, UnsupportedJwtException,SignatureException,IllegalArgumentException{
            final Claims claims = Jwts.parser().setSigningKey(CLAIM_KEY_SECRET).parseClaimsJws(token).getBody();
            if (claims.get(CLAIM_KEY_NAME)==null)
            {
                return  null;
            }
            return  claims.get(CLAIM_KEY_NAME).toString();
    }

    public static String getUserRoleFromToken(String token) throws NullPointerException,
            ExpiredJwtException, UnsupportedJwtException,SignatureException,IllegalArgumentException{
            final Claims claims = Jwts.parser().setSigningKey(CLAIM_KEY_SECRET).parseClaimsJws(token).getBody();
            String auth = claims.get("role").toString();
            int index = auth.lastIndexOf('=');
            int finalIndex =auth.lastIndexOf('}');
            return  claims.get("role").toString().substring(index+1,finalIndex);
    }

}
